import streamlit as st
from streamlit_echarts import st_echarts
import pandas as pd
import numpy as np


def load_data():
    # 读取 CSV 文件
    data = pd.read_csv('拉勾网2223招聘数据.csv')
    return data


def filter_data(data, cities=None, salary_min=None, salary_max=None, educations=None, companies=None, positions=None):
    if cities:
        data = data[data['city'].isin(cities)]
    if salary_min and salary_max:
        data = data[(data['avg_salary'] >= salary_min) & (data['avg_salary'] <= salary_max)]
    if educations:
        data = data[data['education'].isin(educations)]
    if companies:
        data = data[data['companyFullName'].isin(companies)]
    if positions:
        data = data[data['positionName'].isin(positions)]
    return data


# 定义辅助函数，递归转换 numpy 类型为 Python 内置类型
def convert_numpy_types(data):
    if isinstance(data, np.int64):
        return int(data)
    elif isinstance(data, np.float64):
        return float(data)
    elif isinstance(data, list):
        return [convert_numpy_types(item) for item in data]
    elif isinstance(data, dict):
        return {key: convert_numpy_types(value) for key, value in data.items()}
    return data


def bar_chart_question1(data):
    city_counts = data['city'].value_counts().head(10)
    option = {
        "tooltip": {
            "trigger": 'axis',
            "axisPointer": {
                "type":'shadow'
            },
            "formatter": "{b}: {c} 个岗位"
        },
        "xAxis": {
            "type": "category",
            "data": list(city_counts.index),
            "axisLabel": {
                "rotate": 45
            }
        },
        "yAxis": {
            "type": "value"
        },
        "series": [
            {
                "data": list(city_counts.values),
                "type": "bar"
            }
        ]
    }
    # 转换 option 中的 numpy 类型
    option = convert_numpy_types(option)
    st_echarts(options=option, key="bar_chart_question1")


def scatter_chart_question2(data):
    position_avg_salary = data.groupby('positionName')['avg_salary'].mean()
    option = {
        "tooltip": {
            "trigger": 'item',
            "formatter": "{b}: {c}"
        },
        "xAxis": {
            "type": "category",
            "data": list(position_avg_salary.index),
            "axisLabel": {
                "rotate": 45
            }
        },
        "yAxis": {
            "type": "value"
        },
        "series": [
            {
                "data": list(position_avg_salary.values),
                "type": "scatter"
            }
        ]
    }
    # 转换 option 中的 numpy 类型
    option = convert_numpy_types(option)
    st_echarts(options=option, key="scatter_chart_question2")


def rose_chart_question3(data):
    exp_counts = data['workYear'].value_counts()
    option = {
        "tooltip": {
            "trigger": 'item',
            "formatter": "{a} <br/>{b}: {c} ({d}%)"
        },
        "legend": {
            "orient": 'vertical',
            "left": 'left'
        },
        "series": [
            {
                "name": '工作年限',
                "type": 'pie',
                "radius": ['10%', '75%'],
                "center": ['50%', '50%'],
                "roseType": 'area',
                "data": [{"name": exp, "value": count} for exp, count in zip(exp_counts.index, exp_counts.values)]
            }
        ]
    }
    # 转换 option 中的 numpy 类型
    option = convert_numpy_types(option)
    st_echarts(options=option, key="rose_chart_question3")


def grouped_bar_chart_question4(data):
    city_avg_salary = data.groupby('city')['avg_salary'].mean().sort_values(ascending=False).head(10)
    cities = city_avg_salary.index.tolist()
    avg_salaries = [int(salary * 1000) for salary in city_avg_salary.values]  # 转换为元并取整

    option = {
        "tooltip": {
            "trigger": 'axis',
            "axisPointer": {
                "type":'shadow'
            },
            "formatter": "{b}: 平均薪资 {c} 元"
        },
        "legend": {
            "data": ['平均薪资']
        },
        "xAxis": {
            "type": 'category',
            "data": cities,
            "axisLabel": {
                "rotate": 45,
                "interval": 0
            }
        },
        "yAxis": {
            "type": 'value',
            "name": '元',
            "min": 0
        },
        "series": [
            {
                "name": '平均薪资',
                "type": 'bar',
                "data": avg_salaries,
                "label": {
                    "show": True,
                    "position": 'top',
                    "formatter": '{c} 元'
                }
            }
        ]
    }
    
    option = convert_numpy_types(option)
    st_echarts(options=option, key="grouped_bar_chart_question4")


def funnel_chart_question5(data):
    edu_position_counts = data.groupby(['education', 'positionName']).size().reset_index(name='count')
    legend_data = [{"name": position} for position in edu_position_counts['positionName'].unique()]
    half_length = len(legend_data) // 2
    left_legend_data = legend_data[:half_length]
    right_legend_data = legend_data[half_length:]

    option = {
        "tooltip": {
            "trigger": 'item',
            "formatter": "{a} <br/>{b}: {c} ({d}%)"
        },
        "legend": [
            {
                "orient": 'vertical',
                "left": 'left',
                "top": 'center',
                "data": left_legend_data
            },
            {
                "orient": 'vertical',
                "right": 'left',
                "top": 'center',
                "data": right_legend_data
            }
        ],
        "series": [
            {
                "name": '岗位数量',
                "type": 'funnel',
                "left": '10%',
                "top": 20,
                "bottom": 20,
                "width": '70%',
                "min": 0,
                "max": edu_position_counts['count'].max(),
                "minSize": '0%',
                "maxSize": '100%',
                "sort": 'descending',
                "gap": 10,
                "label": {
                    "show": True,
                    "position": 'inside'
                },
                "labelLine": {
                    "length": 10,
                    "lineStyle": {
                        "width": 1,
                        "type":'solid'
                    }
                },
                "itemStyle": {
                    "borderColor": '#fff',
                    "borderWidth": 1
                },
                "data": [{"name": f"{edu} - {pos}", "value": count} for edu, pos, count in
                         zip(edu_position_counts['education'], edu_position_counts['positionName'],
                             edu_position_counts['count'])]
            }
        ]
    }
    # 转换 option 中的 numpy 类型
    option = convert_numpy_types(option)
    st_echarts(options=option, key="funnel_chart_question5")


def main(cities=None, educations=None, companies=None, positions=None, min_salary=0, max_salary=100000):
    st.title('招聘数据分析可视化')
    data = load_data()
    
    # 数据清洗
    data['city'] = data['city'].astype(str)
    data['city'] = data['city'].str.strip()
    data['city'] = data['city'].str.replace(r'[^\w\s]', '', regex=True)
    
    st.sidebar.header('过滤条件')
    
    # 城市筛选
    city_options = sorted(data['city'].unique().tolist())
    cities = st.sidebar.multiselect('选择城市', city_options, default=cities)
    st.session_state.app_cities = cities
    
    # 其他筛选条件
    educations = st.sidebar.multiselect('选择学历', data['education'].unique(), default=educations)
    st.session_state.app_educations = educations
    companies = st.sidebar.multiselect('选择公司', data['companyFullName'].unique(), default=companies)
    st.session_state.app_companies = companies
    
    # 新增：岗位选择
    position_options = sorted(data['positionName'].unique().tolist())
    positions = st.sidebar.multiselect('选择岗位', position_options, default=positions)
    st.session_state.app_positions = positions
    
    # 薪资范围滑块（单位：元）
    min_salary, max_salary = st.sidebar.slider(
        '薪资范围（元）',
        min_value=0,
        max_value=100000,
        value=(min_salary, max_salary),
        step=1000
    )
    st.session_state.app_min_salary = min_salary
    st.session_state.app_max_salary = max_salary
    
    # 应用筛选条件（注意将薪资转换回千元）
    filtered_data = filter_data(
        data,
        cities=cities,
        salary_min=min_salary/1000 if min_salary > 0 else None,
        salary_max=max_salary/1000 if max_salary > 0 else None,
        educations=educations,
        companies=companies,
        positions=positions
    )
    
    # 显示筛选结果摘要
    st.subheader("筛选结果摘要")
    st.write(f"筛选后数据: {len(filtered_data)} 行")
    
    # 检查是否有数据
    if len(filtered_data) == 0:
        st.warning("没有找到符合条件的数据，请调整筛选条件。")
        return  # 直接返回，不显示图表
    
    # 图表展示
    st.header('问题1：不同城市的招聘岗位数量分布')
    bar_chart_question1(filtered_data)

    st.header('问题2：各岗位的平均薪资')
    scatter_chart_question2(filtered_data)

    st.header('问题3：不同工作年限要求下的岗位数量占比')
    rose_chart_question3(filtered_data)

    st.header('问题4：不同城市的平均薪资（前10名）')
    grouped_bar_chart_question4(filtered_data)

    st.header('问题5：不同学历的各岗位的招聘数量')
    funnel_chart_question5(filtered_data)


if __name__ == "__main__":
    main()